{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[this doc on github](https://github.com/dotnet/interactive/tree/main/samples/notebooks/csharp/Docs)\n",
    "\n",
    "# Charts with XPlot\n",
    "Charts can be rendered using [Xplot.Plotly](https://fslab.org/XPlot/). \n",
    "We will cover some example on how to use XPlot in a notebook with the .NET Kernel.\n",
    "\n",
    "First, import the `XPlot.Plotly` namespace:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "vscode": {
     "languageId": "dotnet-interactive.csharp"
    }
   },
   "outputs": [],
   "source": [
    "#r \"nuget: XPlot.Plotly.Interactive, 4.0.6\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "vscode": {
     "languageId": "dotnet-interactive.csharp"
    }
   },
   "outputs": [],
   "source": [
    "using XPlot.Plotly;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The next cell sets up some helpers for data generation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "vscode": {
     "languageId": "dotnet-interactive.csharp"
    }
   },
   "outputs": [],
   "source": [
    "var generator = new Random();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Rendering Scatter plots\n",
    "One of the most commonly used type of chart to explore data set. Use the type `Scatter`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "vscode": {
     "languageId": "dotnet-interactive.csharp"
    }
   },
   "outputs": [],
   "source": [
    "var openSeries = new Scatter\n",
    "{\n",
    "    name = \"Open\",\n",
    "    x = new[] {1, 2, 3, 4},\n",
    "    y = new[] {10, 15, 13, 17}\n",
    "};\n",
    "\n",
    "var closeSeries = new Scatter\n",
    "{\n",
    "    name = \"Close\",\n",
    "    x = new[] { 2,3,4,5 },\n",
    "    y = new[] { 16, 5, 11, 9 }\n",
    "};\n",
    "\n",
    "var chart = Chart.Plot(new[] {openSeries, closeSeries});\n",
    "chart.WithTitle(\"Open vs Close\");\n",
    "display(chart);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's change it to be markers style, so more like a scatter plot."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "vscode": {
     "languageId": "dotnet-interactive.csharp"
    }
   },
   "outputs": [],
   "source": [
    "openSeries.mode = \"markers\";\n",
    "closeSeries.mode = \"markers\";\n",
    "chart = Chart.Plot(new [] {openSeries, closeSeries});\n",
    "display(chart);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`Scatter` can also produce polar charts by setting the radial property `r` and angular proeprty `t`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "vscode": {
     "languageId": "dotnet-interactive.csharp"
    }
   },
   "outputs": [],
   "source": [
    "openSeries = new Scatter\n",
    "{\n",
    "    name = \"Open\",\n",
    "    r = new[] {1, 2, 3, 4},\n",
    "    t = new[] {45, 100, 150, 290}\n",
    "};\n",
    "\n",
    "closeSeries = new Scatter\n",
    "{\n",
    "    name = \"Close\",\n",
    "    r = new[] { 2,3,4,5 },\n",
    "    t = new[] { 16, 45, 118, 90 }\n",
    "};\n",
    "\n",
    "chart = Chart.Plot(new[] {openSeries, closeSeries});\n",
    "chart.WithLayout(new Layout.Layout\n",
    "            {\n",
    "                orientation = -90\n",
    "            });\n",
    "display(chart);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Large scatter plots and performance\n",
    "It is not uncommong to have scatter plots with a large dataset, it is a common scenario at the beginning of a data exploration process. Using the default `svg` based rendering will create performace issues as the dom will become very large.\n",
    "We can then use `web-gl` support to address the problem."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "vscode": {
     "languageId": "dotnet-interactive.csharp"
    }
   },
   "outputs": [],
   "source": [
    "#!time\n",
    "var series = new Scattergl[10];\n",
    "\n",
    "for(var i = 0; i < series.Length; i++){\n",
    "    series[i] =  new Scattergl\n",
    "    {\n",
    "        name = $\"Series {i}\",\n",
    "        mode = \"markers\",\n",
    "        x = Enumerable.Range(0,100000).Select(_ => generator.Next(-200, 200) * 1000 * generator.Next(-2000, 2000)),\n",
    "        y = Enumerable.Range(0,100000).Select(_ => generator.Next(-200, 200) * 1000 * generator.Next(-2000, 2000))\n",
    "    };\n",
    "}\n",
    "\n",
    "chart = Chart.Plot(series);\n",
    "chart.WithTitle(\"Large Dataset\");\n",
    "display(chart);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Can provide custom marker `colour`, `size` and `colorscale` to display even more information to the user."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "vscode": {
     "languageId": "dotnet-interactive.csharp"
    }
   },
   "outputs": [],
   "source": [
    "for(var i = 0; i < series.Length; i++){\n",
    "    var sizes = Enumerable.Range(0,100).Select(_ => (generator.NextDouble() < 0.75) ? generator.Next(1, 5) : generator.Next(10, 15)).ToArray();\n",
    "    var temperatures = sizes.Select(t => (t * 10) - 100);\n",
    "    \n",
    "    series[i].x = Enumerable.Range(0,100).Select(_ => generator.Next(-200, 200) * 1000 * generator.Next(-2000, 2000));\n",
    "    series[i].y = Enumerable.Range(0,100).Select(_ => generator.Next(-200, 200) * 1000 * generator.Next(-2000, 2000));\n",
    "    series[i].marker = new Marker{        \n",
    "        size = sizes,\n",
    "        color = temperatures,\n",
    "        colorscale = \"hot\"    \n",
    "    };\n",
    "}\n",
    "\n",
    "chart = Chart.Plot(series);\n",
    "chart.WithTitle(\"Size and Colour\");\n",
    "display(chart);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Plotly pvoides some additional `color scales` to use."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "vscode": {
     "languageId": "dotnet-interactive.csharp"
    }
   },
   "outputs": [],
   "source": [
    "for(var i = 0; i < series.Length; i++) {\n",
    "    series[i].marker.colorscale = \"Viridis\";\n",
    "}\n",
    "\n",
    "chart = Chart.Plot(series);\n",
    "chart.WithTitle(\"Viridis scale\");\n",
    "display(chart);\n",
    "\n",
    "for(var i = 0; i < series.Length; i++) {\n",
    "    series[i].marker.colorscale = \"Hot\";\n",
    "}\n",
    "\n",
    "chart = Chart.Plot(series);\n",
    "chart.WithTitle(\"Hot scale\");\n",
    "display(chart);\n",
    "\n",
    "for(var i = 0; i < series.Length; i++) {\n",
    "    series[i].marker.colorscale = \"Jet\";\n",
    "}\n",
    "\n",
    "chart = Chart.Plot(series);\n",
    "chart.WithTitle(\"Jet scale\");\n",
    "display(chart);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Rendering Histograms\n",
    "Let's have a look at using histograms, the next cell sets up some generators."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "vscode": {
     "languageId": "dotnet-interactive.csharp"
    }
   },
   "outputs": [],
   "source": [
    "var count = 20;\n",
    "var dates = Enumerable.Range(0, count).Select(i => DateTime.Now.AddMinutes(generator.Next(i, i + 30))).ToArray();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now let's define histogram traces:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "vscode": {
     "languageId": "dotnet-interactive.csharp"
    }
   },
   "outputs": [],
   "source": [
    "var openByTime = new Histogram\n",
    "{\n",
    "    x = dates,\n",
    "    y = Enumerable.Range(0, count).Select(_ => generator.Next(0,200)),\n",
    "    name = \"Open\"\n",
    "};\n",
    "\n",
    "var closeByTime = new Histogram\n",
    "{\n",
    "    x = dates,\n",
    "    y = Enumerable.Range(0, count).Select(_ => generator.Next(0, 200)),\n",
    "    name = \"Close\"\n",
    "};\n",
    "chart = Chart.Plot(new [] {openByTime, closeByTime});\n",
    "display(chart);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Histogram generator will automatically count the number of items per bin. \n",
    "\n",
    "Setting `histfunc` to `\"sum\"` we can now add up all the values contained in each bin.\n",
    "Note that we are creatng bin using the `x` data point and we are using bydefault autobinx"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "vscode": {
     "languageId": "dotnet-interactive.csharp"
    }
   },
   "outputs": [],
   "source": [
    "openByTime.histfunc = \"sum\";;\n",
    "closeByTime.histfunc = \"sum\";\n",
    "chart = Chart.Plot(new [] {openByTime, closeByTime});\n",
    "display(chart);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Area chart and Polar Area chart"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By populating hte property `fill` of a `Scatter` trace the chart will render as area chart.\n",
    "\n",
    "Here is set to `\"tozeroy\"` which will create a fill zone underneath the line reachin to the 0 of the y axis."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "vscode": {
     "languageId": "dotnet-interactive.csharp"
    }
   },
   "outputs": [],
   "source": [
    "openSeries = new Scatter\n",
    "{\n",
    "    name = \"Open\",\n",
    "    x = new[] {1, 2, 3, 4},\n",
    "    y = new[] {10, 15, 13, 17},\n",
    "    fill = \"tozeroy\",\n",
    "    mode= \"lines\"\n",
    "};\n",
    "\n",
    "closeSeries = new Scatter\n",
    "{\n",
    "    name = \"Close\",\n",
    "    x = new[] {1, 2, 3, 4},\n",
    "    y = new[] {3, 5, 11, 9},\n",
    "    fill = \"tozeroy\",\n",
    "    mode= \"lines\"\n",
    "};\n",
    "\n",
    "chart = Chart.Plot(new[] {openSeries, closeSeries});\n",
    "chart.WithTitle(\"Open vs Close\");\n",
    "display(chart);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With one `fill` set to `\"tonexty\"` the cahrt will fill the aread between traces."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "vscode": {
     "languageId": "dotnet-interactive.csharp"
    }
   },
   "outputs": [],
   "source": [
    "openSeries.fill = null;\n",
    "closeSeries.fill = \"tonexty\";\n",
    "\n",
    "chart = Chart.Plot(new[] {openSeries, closeSeries});\n",
    "chart.WithTitle(\"Open vs Close\");\n",
    "display(chart);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using `Area` traces we can generate radial area chart. In this example we are using cardinal points to xpress angular values.\n",
    "The array `{\"North\", \"N-E\", \"East\", \"S-E\", \"South\", \"S-W\", \"West\", \"N-W\"}` will be autoimatically translated to angular values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "vscode": {
     "languageId": "dotnet-interactive.csharp"
    }
   },
   "outputs": [],
   "source": [
    "var areaTrace1 =\n",
    "    new Area\n",
    "    {\n",
    "        r = new[] {77.5, 72.5, 70.0, 45.0, 22.5, 42.5, 40.0, 62.5},\n",
    "        t = new[] {\"North\", \"N-E\", \"East\", \"S-E\", \"South\", \"S-W\", \"West\", \"N-W\"},\n",
    "        name = \"11-14 m/s\",\n",
    "        marker = new Marker\n",
    "        {\n",
    "            color = \"rgb(106,81,163)\"\n",
    "        }\n",
    "    };\n",
    "\n",
    "var areaTrace2 =\n",
    "    new Area\n",
    "    {\n",
    "        r = new  [] {57.49999999999999, 50.0, 45.0, 35.0, 20.0, 22.5, 37.5, 55.00000000000001},\n",
    "        t = new [] {\"North\", \"N-E\", \"East\", \"S-E\", \"South\", \"S-W\", \"West\", \"N-W\"},\n",
    "        name = \"8-11 m/s\",\n",
    "        marker = new Marker{\n",
    "            color = \"rgb(158,154,200)\"\n",
    "        }\n",
    "    };\n",
    "\n",
    "var areaTrace3 =\n",
    "    new Area\n",
    "    {\n",
    "        r = new [] {40.0, 30.0, 30.0, 35.0, 7.5, 7.5, 32.5, 40.0},\n",
    "        t = new [] {\"North\", \"N-E\", \"East\", \"S-E\", \"South\", \"S-W\", \"West\", \"N-W\"},\n",
    "        name = \"5-8 m/s\",\n",
    "        marker = new Marker{\n",
    "            color = \"rgb(203,201,226)\"\n",
    "        }\n",
    "    };\n",
    "\n",
    "var areaTrace4 =\n",
    "    new Area\n",
    "    {\n",
    "        r = new [] {20.0, 7.5, 15.0, 22.5, 2.5, 2.5, 12.5, 22.5},\n",
    "        t = new [] {\"North\", \"N-E\", \"East\", \"S-E\", \"South\", \"S-W\", \"West\", \"N-W\"},\n",
    "        name = \"< 5 m/s\",\n",
    "        marker = new  Marker{\n",
    "            color = \"rgb(242,240,247)\"\n",
    "        }\n",
    "    };\n",
    "\n",
    "var areaLayout = new Layout.Layout\n",
    "{\n",
    "    title = \"Wind Speed Distribution in Laurel, NE\",\n",
    "    font = new Font\n",
    "    {\n",
    "        size = 16\n",
    "    },\n",
    "    legend = new Legend\n",
    "    {\n",
    "        font = new Font\n",
    "        {\n",
    "            size = 16\n",
    "        }\n",
    "    },\n",
    "    radialaxis = new Radialaxis\n",
    "    {\n",
    "        ticksuffix = \"%\"\n",
    "\n",
    "    },\n",
    "    orientation = 270\n",
    "};\n",
    "\n",
    "chart = Chart.Plot(new [] {areaTrace1, areaTrace2, areaTrace3, areaTrace4});\n",
    "chart.WithLayout(areaLayout);\n",
    "display(chart);"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".NET (C#)",
   "language": "C#",
   "name": ".net-csharp"
  },
  "language_info": {
   "file_extension": ".cs",
   "mimetype": "text/x-csharp",
   "name": "C#",
   "pygments_lexer": "csharp",
   "version": "8.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
